package com.littleHan.brushQuestions.web.specificTopic.service.impl;

import com.littleHan.brushQuestions.exception.FailedSettingException;
import com.littleHan.brushQuestions.exception.FailedToDeleteException;
import com.littleHan.brushQuestions.exception.FailedToInsertException;
import com.littleHan.brushQuestions.utils.StringUtil;
import com.littleHan.brushQuestions.utils.SubStringUtil;
import com.littleHan.brushQuestions.web.specificTopic.dao.CommentLikeDao;
import com.littleHan.brushQuestions.web.specificTopic.dao.SpecificTopicDao;
import com.littleHan.brushQuestions.web.specificTopic.pojo.vo.CommentLike;
import com.littleHan.brushQuestions.web.specificTopic.pojo.vo.CommentVo;
import com.littleHan.brushQuestions.web.specificTopic.pojo.vo.TopicPageVo;
import com.littleHan.brushQuestions.web.specificTopic.service.SpecificTopicService;
import com.littleHan.brushQuestions.web.start.pojo.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;

@Service
public class SpecificTopicServiceImpl implements SpecificTopicService {

    @Autowired
    private SpecificTopicDao specificTopicDao;

    @Autowired
    private CommentLikeDao commentLikeDao;

    @Resource
    RedisTemplate redisTemplate;


    @Override
    public Map<String, Object> getTopicInfo(String id) {
        Map<String, Object> map = new HashMap<>();
        //首先获取题目信息
        Topic topic = specificTopicDao.getTopicInfo(id);
        //根据用户id，获取上传题目者
        User user = specificTopicDao.getUserById(topic.getUserId());
        if (user.getAdminId() != null && !"".equals(user.getAdminId())) {
            //管理员(站长)
        } else if (user.getAuditorId() != null && !"".equals(user.getAuditorId())) {
            //审核员
        } else if (user.getGeneralUserId() != null && !"".equals(user.getGeneralUserId())) {
            //普通用户
            GeneralUser generalUser = specificTopicDao.getGeneralUserInfoByIdAndRole(user.getGeneralUserId());
            map.put("uploaderNickName", generalUser.getNickName());
            map.put("icon", generalUser.getIcon());
            //获取其身份信息(通过用户身份表)
            List<Role> roleNameList = specificTopicDao.getRoleName(topic.getUserId());
            map.put("uploaderRole", roleNameList);
        }
        //获取题目难度等级
        String difficult = specificTopicDao.getDiffTypeObj(topic.getDifficultyLevelId());
        String type = specificTopicDao.getDiffTypeObj(topic.getTopicTypeId());
        String object = specificTopicDao.getDiffTypeObj(topic.getObjectId());
        map.put("difficult", difficult);
        map.put("type", type);
        map.put("object", object);
        //将题目中的一些信息清空
        topic.setTitle("");
        //topic.setAnswer("");
        topic.setUserId("");
        topic.setDifficultyLevelId("");
        topic.setTopicTypeId("");
        topic.setObjectId("");
        map.put("topicInfo", topic);
        return map;
    }

    @Override
    public boolean checkIsCollectTopic(String userId, String id) {

        int result = specificTopicDao.checkIsCollectTopic(userId, id);
        if (result < 1) {
            return false;
        }
        return true;
    }

    @Override
    @Transactional(rollbackFor = {FailedSettingException.class})
    public boolean collectAndCancel(String userId, Topic topic) throws FailedSettingException {
        //topic中id为题目id，title为前端对于当前题的状态
        if ("false".equals(topic.getTitle())) {
            int cancelResult = specificTopicDao.cancelCollect(userId, topic.getId());
            if (cancelResult < 1) {
                throw new FailedToDeleteException("取消收藏失败");
            }
            return false;
        } else {
            TopicCollect topicCollect = new TopicCollect();
            topicCollect.setId(StringUtil.generateUUID());
            topicCollect.setUserId(userId);
            topicCollect.setTopicId(topic.getId());
            topicCollect.setTime(StringUtil.getSysTime());
            int collectResult = specificTopicDao.collectTopic(topicCollect);
            if (collectResult < 1) {
                throw new FailedToDeleteException("收藏失败");
            }
            return true;
        }
    }

    /*@Override
    public Map<String, Object> getCommentListOrderByTime(TopicPageVo topicPageVo, String userId) {
        //找出最新的评论按照时间排序，并且分页
        List<CommentVo> commentList = specificTopicDao.getCommentListOrderByTime(topicPageVo.getId(), topicPageVo.getPageNo(), topicPageVo.getPageSize());
        //当前评论是不是该用户评论的(用于用户删除该评论)
        for (CommentVo<String, Object> c : commentList) {
            //查看当前评论赞的个数
            int commentNum = commentLikeDao.getCommentLikeNum(c.getId());
            //查看当前这个评论，该用户是否点赞过
            boolean commentLikeThisUser = commentLikeDao.isThisUserLike(userId, c.getId()) == 1 ? true : false;
            Map<String, Object> map = new HashMap();
            map.put("commentNum", commentNum);
            map.put("commentLikeThisUser", commentLikeThisUser);
            c.setMap(map);
            //是否是当前用户的评论
            int result = specificTopicDao.isUserComment(c.getId(), userId);
            if (result > 0) {
                c.setUserCommentIs(true);
            } else {
                c.setUserCommentIs(false);
            }
        }
        //获取当前题目的总评论数量
        int total = specificTopicDao.getCommentNum(topicPageVo.getId());
        Map<String, Object> map = new HashMap<>();
        map.put("commentList", commentList);
        map.put("total", total);
        return map;
    }*/

    @Override
    public Map<String, Object> getCommentListOrderByTime(TopicPageVo topicPageVo, String userId) {
        //找出最新的评论按照时间排序，并且分页
        List<CommentVo> commentList = specificTopicDao.getCommentListOrderByTime(topicPageVo.getId(), topicPageVo.getPageNo(), topicPageVo.getPageSize());
        //当前评论是不是该用户评论的(用于用户删除该评论)
        for (CommentVo<String, Object> c : commentList) {
            //查看当前评论赞的个数并缓存到redis中
            int commentNum = this.cacheCommentLikeNum(c.getId());
            //查看当前这个评论，该用户是否点赞过
            boolean commentLikeThisUser = this.checkUserIsLike(userId, c.getId());
            Map<String, Object> map = new HashMap();
            map.put("commentNum", commentNum);
            map.put("commentLikeThisUser", commentLikeThisUser);
            c.setMap(map);
            //是否是当前用户的评论
            int result = specificTopicDao.isUserComment(c.getId(), userId);
            if (result > 0) {
                c.setUserCommentIs(true);
            } else {
                c.setUserCommentIs(false);
            }
        }
        //获取当前题目的总评论数量
        int total = specificTopicDao.getCommentNum(topicPageVo.getId());
        Map<String, Object> map = new HashMap<>();
        map.put("commentList", commentList);
        map.put("total", total);
        return map;
    }

    /**
     * 将赞数缓存redis中
     *
     * @param commentId 当前评论的id
     */
    private int cacheCommentLikeNum(String commentId) {
        //首先从redis中获取key为commentId的value值(就是该评论赞的个数)
        Integer num = (Integer) redisTemplate.opsForValue().get(commentId);
        //如果为空那么就从数据库中取，用双重检测机制
        if (num == null) {
            synchronized (this) {
                if (num == null) {
                    //从数据库中获取赞的个数
                    num = commentLikeDao.getCommentLikeNum(commentId);
                    //缓存到数据库中
                    redisTemplate.opsForValue().set(commentId, num);
                    return num;
                }
            }
        }
        return num;
    }

    /**
     * 检查当前用户对当前题目是否点过赞，首先还是要缓存到redis中
     *
     * @param userId    用户id
     * @param commentId 当前评论id
     */
    private boolean checkUserIsLike(String userId, String commentId) {
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("user:").append(commentId).append("::").append(userId);
        Boolean isLike = (Boolean) redisTemplate.opsForValue().get(stringBuilder.toString());
        if (isLike == null) {
            boolean a = commentLikeDao.isThisUserLike(userId, commentId) == 1 ? true : false;
            //redisTemplate.opsForValue().set(stringBuilder.toString(), a);
            return a;
        }
        return isLike;
    }

    @Override
    @Transactional(rollbackFor = {FailedToInsertException.class})
    public void userComment(Comment comment, String userId) throws FailedToInsertException {
        comment.setId(StringUtil.generateUUID());
        comment.setUserId(userId);
        comment.setTime(StringUtil.getSysTime());
        comment.setIsCheck(0);
        int result = specificTopicDao.userComment(comment);
        if (result < 0) {
            throw new FailedToInsertException("评论失败");
        }
    }

    @Override
    @Transactional(rollbackFor = {FailedToInsertException.class})
    public void deleteUserComment(String id, String userId) throws FailedToDeleteException {
        int result = specificTopicDao.deleteUserComment(id, userId);
        if (result != 1) {
            throw new FailedToDeleteException("删除评论失败");
        }
    }

    @Override
    public Boolean commentLike(boolean value, String commentId, String userId) {
        //主要有一个用户加载该评论，那么redis中一点过会有该题目对应的点赞数量，如果为空说明本网站是第一个人访问
        //或者是定时任务清空了redis中的数据，如果是定时任务清空那么让用户手动刷新页面
        if (redisTemplate.opsForValue().get(commentId) == null) {
            return false;
        }
        //value为用户点赞当前这个评论的状态，如果value为false则表示用户要点赞要变为true
        StringBuilder sb = new StringBuilder();
        //redis的key为 评论id::用户id value为boolean型
        sb.append("user:").append(commentId).append("::").append(userId);
        value = !value;
        redisTemplate.opsForValue().set(sb.toString(), value);
        if (value) {
            //点赞+1
            redisTemplate.opsForValue().increment(commentId);
        } else {
            //取消赞-1
            redisTemplate.opsForValue().decrement(commentId);
        }
        return null;
    }

    @Override
    public String updateCommentLike() {
        //获取redis中key的前缀为user的键值对
        Set<String> keys = redisTemplate.keys("user".concat("*"));
        //点赞类实例的集合
        List<CommentLike> commentLikes = new ArrayList<>();
        //取消点赞的实例集合
        List<CommentLike> cancelCommentLikes = new ArrayList<>();
        for (String k : keys) {
            //SubStringUtil.subStringRedisKeyFront(k)截取commentId
            //SubStringUtil.subStringRedisKeyAfter(k)截取用户id(非general_user_id)
            String userId = SubStringUtil.subStringRedisKeyAfter(k);
            String generalUserId = commentLikeDao.getGeneralUserId(userId);
            String commentId = SubStringUtil.subStringRedisKeyFront(k);
            //根据commentId检查评论表是否还有该评论了，防止评论的用户删除了评论，此时就不能点赞或者去取消点赞
            boolean isLive = commentLikeDao.selectCommentById(commentId) == 1 ? true : false;
            if (isLive) {
                //如果value得到值为true那么就说明用户点赞，就需要插入到点赞表中
                if ((boolean) redisTemplate.opsForValue().get(k)) {
                    //点赞
                    commentLikes.add(new CommentLike(StringUtil.generateUUID(), commentId, generalUserId));
                } else {
                    //取消赞
                    cancelCommentLikes.add(new CommentLike(commentId, generalUserId));
                }
            }
        }
        int flag = 0;
        //如果点赞集合有数据，那么就进行持久化
        if (commentLikes.size() > 0) {
            System.out.println(commentLikes);
            //将所有点赞记录持久化到mysql中
            commentLikeDao.insertCommentLike(commentLikes);
            flag = 1;
        }
        //将取消喜欢的批量删除

        if (cancelCommentLikes.size() > 0) {
            System.out.println(cancelCommentLikes);
            commentLikeDao.deleteCancelCommentLike(cancelCommentLikes);
            flag = 1;
        }
        if (flag == 1) {
            //删除redis中所有数据
            Set<String> allKeys = redisTemplate.keys("*");
            redisTemplate.delete(allKeys);
        }
        return null;
    }
}
